<!doctype html>
<html class="dark" xmlns:x-transition="" lang="eng">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="icon" type="image/png" sizes="32x32" href="../static/favicon-32x32.png">
    <link rel="icon" type="image/png" sizes="16x16" href="../static/favicon-16x16.png">
    <link rel="mask-icon" href="../static/safari-pinned-tab.svg" color="#0ed3cf">
    <meta name="msapplication-TileColor" content="#da532c">
    <meta name="theme-color" content="#0ed3cf">

    <title>Piano LED Emulator</title>
</head>

<body style="background-color: #000000;">

<canvas id="ledemu1" style="width: 100%;">
</canvas>

<canvas id="ledemu2" style="width: 100%;">
</canvas>

<canvas id="ledemu3" style="width: 96vmin; height: 96vmin">
</canvas>

<script>
    let socket;
    const ledemu1 = document.getElementById("ledemu1");
    var ctx1 = ledemu1.getContext('2d');
    ctx1.canvas.width = window.innerWidth;
    ctx1.canvas.height = 30;
    ctx1.fillStyle = "#000000";
    ctx1.fillRect(0, 0, ctx1.canvas.width, ctx1.canvas.height);

    const ledemu2 = document.getElementById("ledemu2");
    var ctx2 = ledemu2.getContext('2d');
    ctx2.canvas.width = window.innerWidth;
    ctx2.canvas.height = 50;

    const ledemu3 = document.getElementById("ledemu3");
    var ctx3 = ledemu3.getContext('2d');
    ctx3.canvas.width = window.innerWidth;
    ctx3.canvas.height = 600;

    function establish_socket_connection() {
        console.log("Connecting to websocket")
        socket = new WebSocket('ws://' + window.location.hostname + ':8765/ledemu');

        socket.addEventListener('open', function (event) {
            console.log('Connected to server');
        });
        var count = 0;
        socket.addEventListener('message', function (event) {
            count++;
            const msg = JSON.parse(event.data);
            if ("leds" in msg) {
                bar(ledemu1, ctx1, msg.leds);
                lights(ledemu2, ctx2, msg.leds);
                ring(ledemu3, ctx3, msg.leds);
            }
        });
        socket.addEventListener('close', function (event) {
            console.log('Connection closed.');
        });

        socket.addEventListener('error', function (event) {
            console.log('WebSocket error: ', event);
        });
    }

    establish_socket_connection();

    window.onbeforeunload = function () {
        socket.onclose = function () {
        }; // disable onclose handler first
        socket.close();
    };

    // Commenting out: we need updates since virtual keyboard may be in foreground
    /*
    window.addEventListener('focus', () => {
        console.log("Gained focus");
        socket.send(JSON.stringify({"cmd": "resume"}));
    })
    window.addEventListener('blur', () => {
        console.log("Lost focus");
        socket.send(JSON.stringify({"cmd": "pause"}));
    })
    */


    function bar(canvas, ctx, leds) {
        ledwidth = canvas.width / leds.length;
        for (let i = 0; i < leds.length; i++) {
                red = leds[i] >> 16 & 0xFF;
                green = leds[i] >> 8 & 0xFF;
                blue = leds[i] & 0xFF;

                red = (red / 255) ** (1/2.2);
                green = (green / 255) ** (1/2.2);
                blue = (blue / 255) ** (1/2.2);

                red = Math.round(red * 255);
                green = Math.round(green * 255);
                blue = Math.round(blue * 255);

                ctx.fillStyle = `rgb(${red} ${green} ${blue})`;
                ctx.fillRect(i*ledwidth, 10, ledwidth, 10);
        }
    }

    function lights(canvas, ctx, leds) {
        ledwidth = canvas.width / leds.length;

        ctx.fillStyle = "rgb(0,0,0)";
        ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);

        for (let i = 0; i < leds.length; i++) {
            red = leds[i] >> 16 & 0xFF;
            green = leds[i] >> 8 & 0xFF;
            blue = leds[i] & 0xFF;

            red = (red / 255) ** (1/2.2);
            green = (green / 255) ** (1/2.2);
            blue = (blue / 255) ** (1/2.2);

            ctx.save();
            ctx.translate(i*ledwidth + ledwidth/2, 25);
            ctx.globalCompositeOperation = "lighten";

            const bloom = ledwidth * 4;
            grad = ctx.createRadialGradient(0, 0, 1, 0, 0, bloom);
            grad.addColorStop(0, `rgb(${red*100}%, ${green*100}%, ${blue*100}%)`);
            grad.addColorStop(0.2, `rgb(${red**2.2*80}%, ${green**2.2*80}%, ${blue**2.2*80}%)`);
            grad.addColorStop(1, 'rgb(0,0,0)');

            ctx.fillStyle = grad;
            ctx.fillRect(-bloom, -bloom, bloom*2, bloom*2);

            ctx.restore();
        }
    }

    function ring(canvas, ctx, leds) {
        const canvas_dim = Math.min(canvas.clientWidth, canvas.clientHeight);
        canvas.clientWidth = canvas_dim;
        canvas.clientHeight = canvas_dim;
        canvas.width = canvas_dim;
        canvas.height = canvas_dim;
        const dim = Math.min(canvas.width, canvas.height);

        ctx.fillStyle = "rgb(0,0,0)";
        ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
        const numleds = leds.length;
        for (let i = 0; i < numleds; i++) {
            red = leds[i] >> 16 & 0xFF;
            green = leds[i] >> 8 & 0xFF;
            blue = leds[i] & 0xFF;

            red = (red / 255) ** (1/2.2);
            green = (green / 255) ** (1/2.2);
            blue = (blue / 255) ** (1/2.2);

            ctx.save();
            const pos = i/numleds;
            const partial_circle = pos * 0.9 + 0.05;
            const posrad = partial_circle * 2 * Math.PI;
            x = Math.cos(posrad + Math.PI/2);   // + Math.PI/2 to rotate origin to bottom
            y = Math.sin(posrad + Math.PI/2);

            ctx.translate(x * dim*0.4 + dim/2, y * dim*0.4 + dim/2);
            ctx.globalCompositeOperation = "screen";

            const bloom = dim * 0.08;
            grad = ctx.createRadialGradient(0, 0, 0.1, 0, 0, bloom);
            grad.addColorStop(0, `rgb(${red*250}%, ${green*250}%, ${blue*250}%)`);
            grad.addColorStop(0.08, `rgb(${red*150}%, ${green*150}%, ${blue*150}%)`);
            grad.addColorStop(0.13, `rgb(${red**2.2*25}%, ${green**2.2*25}%, ${blue**2.2*25}%)`);
            grad.addColorStop(1, 'rgb(0,0,0)');

            ctx.fillStyle = grad;
            ctx.fillRect(-bloom, -bloom, bloom*2, bloom*2);

            ctx.restore();
        }
    }

</script>

</body>
